package com.baofu.paycore.service;

import com.baofu.paycore.biz.model.BackPayBO;
import com.baofu.paycore.biz.paycore.handler.impl.FreezeHandler;
import com.baofu.paycore.biz.paycore.handler.impl.UnfreezeHandler;
import com.baofu.paycore.common.enums.RedisKeyEnum;
import com.baofu.paycore.common.utils.ExceptionUtil;
import com.baofu.paycore.common.utils.RedisKeyUtil;
import com.baofu.paycore.manager.cache.RedisManager;
import com.baofu.paycore.manager.model.FreezeBO;
import com.baofu.paycore.manager.storer.FreezeOrderRepository;
import com.baofu.paycore.service.converter.BO2DTOConverter;
import com.baofu.paycore.service.facade.FreezeServiceFacade;
import com.baofu.paycore.service.facade.model.AccountFreeze.FreezeDTO;
import com.baofu.paycore.service.facade.model.AccountFreeze.FreezeResDTO;
import com.baofu.paycore.service.facade.model.AccountFreeze.UnfreezeDTO;
import com.baofu.paycore.service.facade.model.withdraw.WithdrawResDTO;
import com.baofu.paycore.service.factory.impl.FreezeFactoryImpl;
import com.baofu.paycore.service.factory.impl.UnfreezeFactoryImpl;
import com.baofu.paycore.service.validate.account.FreezeValidate;
import com.baofu.paycore.service.validate.account.UnfreezeValidate;
import com.system.commons.result.Result;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.MDC;
import org.slf4j.helpers.SystemMarker;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

/**
 * <p>
 * </p>
 * User:ames wang  Date: 2017/6/22
 */
@Slf4j
@Service
public class FreezeService implements FreezeServiceFacade {

    @Autowired
    private FreezeValidate freezeValidate;

    @Autowired
    private FreezeFactoryImpl freezeFactory;

    @Autowired
    private FreezeOrderRepository freezeOrderRepository;

    @Autowired
    private FreezeHandler freezeHandler;

    @Autowired
    private UnfreezeValidate unfreezeValidate;

    @Autowired
    private UnfreezeFactoryImpl unfreezeFactory;

    @Autowired
    private UnfreezeHandler unfreezeHandler;

    /**
     * redis服务
     */
    @Autowired
    private RedisManager redisManager;


    /**
     * 冻结接口
     *
     * @param freezeDTO               解冻请求参数
     * @param traceLogId                日志ID
     * @return                          结果
     *                                  response.isSuccess()标示方法的远程调用状态，方法实际执行结果从result 取值
     */
    @Override
    public Result<FreezeResDTO> freeze(FreezeDTO freezeDTO, String traceLogId) {
        long start = System.currentTimeMillis();
        Result<FreezeResDTO> result = null;
        boolean flag = false;
        try {
            MDC.put(SystemMarker.TRACE_LOG_ID, traceLogId);

            log.info("冻结请求参数,FreezeDTO:{}", freezeDTO);
            flag = freezeValidate.lock(freezeDTO);

            //1.请求参数校验
            freezeValidate.paramsValidate(freezeDTO);
            //幂等性控制
            result = freezeValidate.validateUniqueOrder(freezeDTO, freezeOrderRepository);
            if (result != null) {
                return result;
            }

            //2、请求对象转换
            FreezeBO freezeBO = freezeFactory.build(freezeDTO);
            freezeBO.setTradeLogId(traceLogId);

            //3、支付相关信息落地
            freezeOrderRepository.addOrder(freezeBO);

            //4.业务流程处理
            BackPayBO backPayBO = freezeHandler.process(freezeBO);

            //5、接口返回对象生成
            FreezeResDTO freezeResDTO = BO2DTOConverter.getFreezeResDTO(backPayBO);
            result = new Result<>(freezeResDTO);

        } catch (Exception e) {
            log.error("冻结异常:{}", e);
            result = ExceptionUtil.doExceptionService(e, FreezeResDTO.class);
        } finally {
            log.info("freeze 耗时:{} 冻结结果:{}", System.currentTimeMillis() - start, result);
            freezeValidate.release(freezeDTO, flag);
            MDC.clear();
        }
        return result;
    }


    /**
     * 冻结解冻接口
     *
     * @param unfreezeDTO               解冻请求参数
     * @param traceLogId                日志ID
     * @return                          结果
     *                                  response.isSuccess()标示方法的远程调用状态，方法实际执行结果从result 取值
     */
    @Override
    public Result<WithdrawResDTO> unFreeze(UnfreezeDTO unfreezeDTO, String traceLogId) {
        Result<WithdrawResDTO> result = null;
        boolean flag = false;
        try {
            MDC.put(SystemMarker.TRACE_LOG_ID, traceLogId);
            log.info("解冻请求参数:withdrawDTO {}", unfreezeDTO);
            //分布式锁
            flag = unfreezeValidate.lock(unfreezeDTO);

            //1.参数合理性检验
            unfreezeValidate.paramsValidate(unfreezeDTO);
            //幂等性控制
            result = unfreezeValidate.validateUniqueOrder(unfreezeDTO, freezeOrderRepository);
            if (result != null) {
                return result;
            }
            //2、请求对象转换
            FreezeBO freezeBO = unfreezeFactory.build(unfreezeDTO);
            freezeBO.setTradeLogId(traceLogId);

            //3、解冻相关信息落地
            freezeOrderRepository.addOrder(freezeBO);

            //4.业务流程处理
            BackPayBO backPayBO = unfreezeHandler.process(freezeBO);

            //5、接口返回对象生成
            WithdrawResDTO withdrawResDTO = BO2DTOConverter.getWithdrawResDTO(backPayBO);
            result = new Result<>(withdrawResDTO);
        } catch (Exception e) {
            log.error("解冻异常:{}", e);
            result = ExceptionUtil.doExceptionService(e, WithdrawResDTO.class);
        } finally {
            log.info("unfreeze  解冻结果:{}", result);
            unfreezeValidate.release(unfreezeDTO, flag);
            //清redis缓存
            redisManager.deleteObject(RedisKeyUtil.buildRedisKey(RedisKeyEnum.PAY_ACC_UNFREEZE, unfreezeDTO.getOrigPayNo()));
            MDC.clear();
        }
        return result;

    }
}
